package com.jbit.hxy.controller;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.util.WxMaConfigHolder;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.jbit.hxy.common.Result;
import com.jbit.hxy.enums.WxUserStatusEnum;
import com.jbit.hxy.model.dto.*;
import com.jbit.hxy.model.po.WxUser;
import com.jbit.hxy.service.user.SmsService;
import com.jbit.hxy.service.user.WxUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.modelmapper.ModelMapper;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.Optional;
import java.util.concurrent.ExecutionException;

@RestController
@RequestMapping("/user")
@RequiredArgsConstructor
@Tag(name = "用户模块")
@Slf4j
public class WxUserController {


    private final WxUserService userService;
    private final SmsService smsService;
    private final StringRedisTemplate stringRedisTemplate;
    private final ModelMapper modelMapper;
    /**
     * 微信小程序核心服务组件
     */
    private final WxMaService wxMaService;


    @Operation(summary = "绑定手机号")
    @PostMapping("/bindPhone")
    public Result bindPhone(@RequestBody WxMaPhoneDTO dto){
        try {
            WxMaPhoneNumberInfo newPhoneNoInfo = this.wxMaService.getUserService().getNewPhoneNoInfo(dto.getCode());
            String phone = newPhoneNoInfo.getPurePhoneNumber();
            WxUser userPo = userService.getUserByOpenId(dto.getOpenid());
            userPo.setPhoneNumber(phone);
            userService.updateById(userPo);
            return Result.success(userPo);
        } catch (WxErrorException e) {
            return Result.error(e.getError().getErrorMsg());
        }
    }



    @Operation(summary = "微信授权登录")
    @PostMapping("/authLogin")
    public Result wxAuthLogin(@RequestBody WxMaLoginDTO dto){
        try {
            WxMaJscode2SessionResult session =
                    wxMaService.getUserService().getSessionInfo(dto.getCode());
            if (session != null && !StringUtils.isEmpty(session.getOpenid())) {
                WxUser loginUser = userService.getUserByOpenId(session.getOpenid());
                if(loginUser == null) {
                    loginUser = new WxUser();
                    loginUser.setHeadImgUrl(dto.getAvatarUrl());
                    loginUser.setNickName(dto.getNickName());
                    loginUser.setOpenid(session.getOpenid());
                    loginUser.setCreateTime(LocalDateTime.now());
                    loginUser.setUpdateTime(LocalDateTime.now());
                    userService.save(loginUser);
                }
                return Result.success(loginUser);
            }
            else {
                return Result.fail("授权登录失败");
            }
        } catch (WxErrorException e) {
            return Result.error(e.getError().getErrorMsg());
        } finally {
            WxMaConfigHolder.remove();//清理ThreadLocal
        }
    }



    @Operation(summary = "账号登录",description = "")
    @PostMapping("/loginPassword")
    public Result loginWithPassword(@RequestBody @Validated PhonePasswordDTO dto){
        WxUser wxUser = userService.getUserByPhoneNumber(dto.getPhone());
        Optional<WxUser> wxUserOpt = Optional.ofNullable(wxUser);
        if (wxUserOpt.isPresent()){
            wxUser = wxUserOpt.get();
            if (! wxUser.getPassword().contentEquals(dto.getPassword())){
                return Result.fail("密码输入错误");
            }
            else if(wxUser.getStatus() == WxUserStatusEnum.LOCKED.getValue()){
                return Result.fail("该账号已被锁定");
            }
            else {
                wxUser.setPassword(null);
                return Result.success(wxUser);
            }
        }
        else {
            return Result.fail("该手机号未注册");
        }

    }

    @Operation(summary = "短信登录",description = "")
    @PostMapping("/loginSmsCode")
    public Result loginWithSmsCode(@RequestBody @Validated PhoneSmsCodeDTO dto){
        ValueOperations<String, String> vo = stringRedisTemplate.opsForValue();
        String redisCode = vo.get(dto.getPhone());
        if (StrUtil.isBlank(redisCode)){
            return Result.fail("验证码已过期");
        }
        if(! redisCode.contentEquals(dto.getCode())){
           return Result.fail("验证码错误");
        }
        WxUser wxUser = userService.getUserByPhoneNumber(dto.getPhone());
        if(wxUser.getStatus() == WxUserStatusEnum.LOCKED.getValue()){
            return Result.fail("此账号已被锁定");
        }
        wxUser.setPassword(null);
        return Result.success(wxUser);
    }

    @Operation(summary = "发送短信",description = "")
    @PostMapping("/sendCode")
    public Result sendCode(@RequestParam(value = "phone",required = true) String phone) throws ExecutionException, InterruptedException {
        if(! StringUtils.hasLength(phone.trim())) {
            return Result.fail("手机号不能为空");
        }
        if(! phone.matches("^1[3456789]\\d{9}$")) {
            return Result.fail("手机号格式不正确");
        }
        return smsService.sendSms(phone);
    }


    /**
     * 注册新用户
     * @param dto
     * @return
     */
    @Operation(summary = "用户注册",description = "")
    @PostMapping("/register")
    public Result registerUser(@RequestBody @Validated RegisterUserDTO dto){
        WxUser userEntity = userService.getUserByPhoneNumber(dto.getPhoneNumber());
        if(userEntity != null){
            return Result.fail("此手机号已被注册");
        }
        else if(! dto.getPassword().equals(dto.getConfirmPassword())){
            return Result.fail("两次输入密码不一致");
        }
        else {
            ValueOperations<String, String> vo = stringRedisTemplate.opsForValue();
            String redisCode = vo.get(dto.getPhoneNumber());
            if(StrUtil.isBlank(redisCode)) {
                return Result.fail("验证码已过期");
            }
            else if(! dto.getCode().equals(redisCode)) {
                return Result.fail("验证码错误");
            }
            //将DTO转换为实体对象
            WxUser newUser = modelMapper.map(dto, WxUser.class);
            //用户昵称：获取手机号后四位作为昵称基础，再加上一些固定字符，如 “用户_1234”
            newUser.setNickName("用户_" + dto.getPhoneNumber().substring(7));
            newUser.setStatus(WxUserStatusEnum.NORMAL.getValue());
            newUser.setHeadImgUrl("upload/headImg/default.jpg");
            userService.createUser(newUser);
            return Result.success("新用户注册成功");
        }
    }

    /**
     * 忘记密码
     * @param dto
     * @return
     */
    @Operation(summary = "忘记密码",description = "")
    @PostMapping("/forgetPassword")
    public Result forgetPassword(@RequestBody @Validated ForgetPasswordDTO dto){
        WxUser userEntity = userService.getUserByPhoneNumber(dto.getPhone());
        if(userEntity == null){
            return Result.fail("该手机号码不存在");
        }
        else if(! dto.getPassword().equals(dto.getConfirmPassword())){
            return Result.fail("两次输入密码不一致");
        }
        else {
            ValueOperations<String, String> vo = stringRedisTemplate.opsForValue();
            String redisCode = vo.get(dto.getPhone());
            if (StrUtil.isBlank(redisCode)) {
                return Result.fail("验证码已过期");
            } else if (!dto.getCode().equals(redisCode)) {
                return Result.fail("验证码错误");
            }
            else if(userEntity.getPassword().equals(dto.getPassword())) {
                return Result.fail("新密码不能与旧密码相同");
            }
            else {
                // 用来构造更新条件
                LambdaUpdateWrapper<WxUser> updateWrapper = new LambdaUpdateWrapper();
                updateWrapper.set(WxUser::getPassword, dto.getPassword());
                updateWrapper.eq(WxUser::getId, userEntity.getId());
                userService.update(null,updateWrapper);
                return Result.success("密码修改成功");
            }
        }
    }
    @PostMapping("/updateAvatarById")
    @Operation(summary = "修改头像",description = "根据Id修改头像")
    public Result updateAvatarById(@RequestBody UpdateAvatarDTO updateAvatarDTO){
        WxUser wxUser = userService.getById(updateAvatarDTO.getId());
        if(wxUser != null){
            wxUser.setHeadImgUrl(updateAvatarDTO.getUrl());
            userService.updateById(wxUser);
            return Result.success(wxUser);
        }
        else{
            return Result.fail("用户不存在");
        }
    }
    @GetMapping("/getUserByOpenId")
    @Operation(summary = "根据openId获取用户",description = "")
    public Result getUserByOpenId(@RequestParam(value = "openid") String openid){
        WxUser wxUser = userService.getUserByOpenId(openid);
        if(wxUser != null){
            return Result.success(wxUser);
        }
        else{
            return Result.fail("用户不存在");
        }

    }

}
